﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using DyUi.Base.Constants;
using DyUi.Base.Interfaces;
using DyUi.Base.Interfaces.Services;
using DyUi.Base.Interfaces.SubSystems;
using DyUi.Core;

namespace DyUi.Base.SubSystems
{
    public class ExecutionSubSystem : DyUiControllerSubSystem, IExecutionSubSystem
    {
        [ImportMany]
        public IEnumerable<ExportFactory<IExecutionService, IScriptHostMetaData>> CodeExecutionHosts { get; set; }
        
        public Dictionary<String, ExportFactory<IExecutionService, IScriptHostMetaData>> CodeExecutionHostsMap { get; set; }

        public IEnumerable<String> AllowedScriptHosts { get; set; }

        public IEnumerable<String> ScriptHostPriority { get; set; }

        public override void Prepare()
        {
            base.Prepare();

            CodeExecutionHostsMap = new Dictionary<String, ExportFactory<IExecutionService, IScriptHostMetaData>>();

            using (var calalog = new DirectoryCatalog(Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName, "*ScriptHost*.dll"))
            {
                try
                {
                    var compositionContainer = new CompositionContainer(calalog);
                    compositionContainer.ComposeParts(this);
                }
                catch (Exception ex)
                {
                    Debug.Write(ex);
                    throw;
                }
            }

            AllowedScriptHosts = (Controller.SettingsSubSystem[SettingsKeys.AllowedScriptHosts] ?? String.Empty).Split(',');
            ScriptHostPriority = (Controller.SettingsSubSystem[SettingsKeys.ScriptHostPriority] ?? String.Empty).Split(',');

            CodeExecutionHostsMap =
                CodeExecutionHosts
                .Select(a => new { Name = a.Metadata.Name, Value = a })
                .Where(a => AllowedScriptHosts.Contains(a.Name))
                .ToDictionary(a => a.Name, a => a.Value);
        }
        
        public virtual IExecutionService ResolveExecutionHost(IDyUiComponent component)
        {
            foreach (var host in ScriptHostPriority)
            {
                var hostFactory = null as ExportFactory<IExecutionService, IScriptHostMetaData>;

                if (!CodeExecutionHostsMap.TryGetValue(host, out hostFactory) || hostFactory == null)
                {
                    continue;
                }

                if (component is IDyUiControl)
                {
                    var control = (IDyUiControl)component;

                    var scriptPath = Path.Combine(control.Path.FullName,String.Format("{0}.{1}", control.DyUiName, hostFactory.Metadata.Extension));

                    if (File.Exists(scriptPath))
                    {
                        return hostFactory.CreateExport().Value;
                    }
                }
            }

            return null;
        }
    }
}
